class window.Game extends window.Screen
  constructor : (@ctx) ->
    @inp = window.Input
    @draw = @ctx.SpriteRender()
    @shapeRender = new window.ShapeRender @
    @vx = 0
    @vy = 0

    @textToRender = []
    @tiles = new window.Tilemap @, 32, 32


    @restore()

    window.game = @
  
  makeBlood : (x, y, m) ->
    m ?= 3
    b = new window.BloodParticles 4 + (3 * Math.random()) | 0
    b.init @
    b.x = x
    b.y = y
    @blood.push b
    
  makeSound : (x, y, loudness) ->
    if loudness < 5.0
      return
    
    for e in @entities
      if not e.hasTag "guard"
        continue
      if e.isDead()
        continue
      dx = e.x - x
      dy = e.y - y
      d = Math.sqrt(dx * dx + dy * dy)
      if d >= loudness 
        continue 
      e.hear x, y


  deleteEntity : (e) -> 
    e.isRemoved = true

    @entitiesToDelete.push e

  getTile : (x, y) ->
    @tiles.getTile x, y

  addEntity : (e) ->
    e.init @
    @entities.push e
    e

  getEntities : (fn) ->
    for e in @entities
      if not fn e
        continue
      e

  getEntitiesWithTag : (tag) ->
    for e in @entities
      if not e.hasTag tag
        continue
      e

  load : () ->
    defer = new window.mq.Defer()


    @font =  @ctx.Font437()
    @spriteSheet =  @ctx.Texture()
    imgPromise = @spriteSheet.load "img/sprites.png"
    me = @

    

    window.mq.all([@font.promise, imgPromise]).then () ->
      me.draw.setSpriteSheet me.spriteSheet, 16, 16

      defer.resolve true

    defer
  
  restore : () ->
    @killCount = 0
    @unnoticed = true
    @alertedGuardsCount = 0

    @entitiesToDelete = []
    @entities = []
    @blood = []

    #@addEntity new Player()

    wg = new window.WindowGenerator()
    @tiles.tiles = {}
    wg.generateWorld @, @tiles
    @tiles.generateTileMesh()

    @viewport = new window.Transform2D()
    @identity = new window.Transform2D()


  drawString : (x, y, msg, scale, r, g, b, a) -> @textToRender.push [x, y, msg, scale, r, g, b, a, false]
  drawStringOutlined : (x, y, msg, scale, r, g, b, a) -> @textToRender.push [x, y, msg, scale, r, g, b, a, true]

  update : () ->
    for e in @entitiesToDelete
      index = @entities.indexOf e
      @entities.splice index, 1 if index != -1
    @entitiesToDelete = []

    moving = []
    
    for b in @blood
      b.update()

    for e in @entities
      x0 = e.x | 0
      y0 = e.y | 0
      e.update()
      x1 = e.x | 0
      y1 = e.y | 0
      moving.push [x0, y0, x1, y1, e] if x0 != x1 or y0 != y1

    collided = []
    for [x0, y0, x1, y1, e] in moving
      slide = window.physics.calculateSlide @tiles, e, x0, y0, x1, y1

      if slide[0] != x1 or slide[1] != y1 
        e.slideCollide slide

      endx = e.x
      endy = e.y

      collided.push [x0, y0, endx, endy, e]

    for [x0, y0, x1, y1, e] in collided
      if e.isRemoved == true
        continue

      dx = x1 - x0
      dy = y1 - y0

      b1 = 
        x : x0 + e.boffx()
        y : y0 + e.boffy()
        w : e.bwidth()
        h : e.bheight()
        vx : dx
        vy : dy

      for o in @entities
        continue if o.isRemoved == true or o == e

        b2 = 
          x : o.boffx() + o.x
          y : o.boffy() + o.y
          w : o.bwidth()
          h : o.bheight()


        if window.physics.sweptAABB(b1, b2).t < 1.0
          e.collidedWith o

  canSeeTile : (e, t) ->
    tiles = @tiles
    x0 = (e.x / 64) | 0
    y0 = (e.y / 64) | 0
    x1 = t.x
    y1 = t.y
    return not window.physics.line x0, y0, x1, y1, (x, y) ->
      return false if x == x0 or y == y0 or x1 == x or y == y1
      return true if tiles.isSolid x0, y0, x1, y1
      return false

  canSee : (e, who) ->
    x0 = e.x
    y0 = e.y
    x1 = who.x
    y1 = who.y
    tiles = @tiles
    return not window.physics.line x0, y0, x1, y1, (x, y) ->
      if tiles.simpleIntersectSolid(x, y, e)
        return true
      return false

  getPath : (e, x1, y1) ->
    return @tiles.pathFromTo e, x1, y1

  render : () ->
    @viewport.setTranslation @vx, @vy
    @tiles.render()

    @draw.use()
    @draw.setWorldTransform @viewport
    for b in @blood
      b.render()
    
    for d in @entities
      if d.isDead()
        d.render()


    entitiesToRender = []

    for e in @entities
      if not e.isDead()
        entitiesToRender.push e

    entitiesToRender.sort (a, b) -> a.y + a.boffy() + a.bheight() > b.y + b.boffy() + b.bheight()
    
    for e in entitiesToRender
      e.render()
      
    @draw.setWorldTransform @identity
    @shapeRender.render()

    @font.use()
    for txt in @textToRender
      [x, y, msg, scale, r, g, b, a, o] = txt
      @font.drawString x, y, msg, scale if o == false
      @font.drawOutlined x, y, msg, scale, r, g, b, a if o == true

    @textToRender = []
